#######################################################
# The class of Finite & Stochastic DEVS  
# Author: moonho.hwang@gmail.com
#   Date: Oct.19.2011
#######################################################
from XSY.DEVS.Simulatable import *
from XSY.Set.RandomVariables import *
from XSY.Set.Interval import *
#from XSY.Graph.Graph import *
from XSY.hashdict import *
from XSY.Base import *

class FSDEVS(Simulatable):
   ''' the class of finite stochastic DEVS having the finite set of states and transitions 
The external and internal (with output) transitions, and time advance can be probability functions whose sum of all possibility is equal to 1. 
   '''
   def __init__(m, name, parent=None):
      '''constructor:'''
      Simulatable.__init__(m, name, parent), 
  
   def rv_delta_0(m):
      '''the initial state probability (V * N, [0,1]) ''' 
      raise Exception("%s is not overrided!"%function_name())
      #return DRV({s:p,...})

   def delta_0(m):
      '''reset the initial state'''      
      rv_s0 = m.rv_delta_0()

      if isinstance(rv_s0, DRV) : 
         s0 = rv_s0.sample()
         m.set_state(s0)
      else:
         m.set_state(rv_s0)

   def rv_tau(m):
      '''the random lifespan scheduling function'''
      raise Exception("%s is not overrided!"%function_name())
      #return RandomVariable

   def ta(m):
      '''time advance'''
      rv_ta = m.rv_tau()
      if isinstance(rv_ta, RandomVariable): 
         return rv_ta.sample()
      else:
         return rv_ta
 
   def rv_delta_x(m, x):
      '''the random variables of the next state and reschedule triggered by an external event x'''
      raise Exception("%s is not overrided!"%function_name())
      #return DRV({(rho,s):p,...})

   def delta_x(m, x):
      '''the external transition'''
      rv_d_x = m.rv_delta_x(x) 
      #print "rv_d_x=",rv_d_x, "index_table=",index_table

      if rv_d_x == None:
         return False
      elif isinstance(rv_d_x, DRV):
         (rho,s)=rv_d_x.sample()
         #print "edge=",edge
         m.set_state(s)
	 return rho
      else: # no arc -> no change including no reschedule
         m.set_state(rv_d_x[1])
         return rv_d_x[0]

   def Delta_x(self, x, t):
      '''inject (x,t) into the Simulatable to generate next state'''
      if t < self.timeLast() or t> self.timeNext(): 
         raise Exception("Delta_x scheduling error tL=%s, t=%s, tN=%s"%(self.timeLast(), t, self.timeNext()) )
      self.Delta_null(t)
      rho = self.delta_x(x)
      if rho:
         self.set_timeLast(t)
         self.set_timeNext(t + self.ta())

   def rv_delta_y(m):
      '''the random variable for output and internal state transition''' 
      raise Exception("%s is not overrided!"%function_name())
      #return DRV({(y,s):p,...})
 
   def delta_y(m):
      '''the output and internal transition'''
      rv_d_y = m.rv_delta_y() 
      #print "rv_d_y=",rv_d_y, "index_table=",index_table
      m.y = None
      if rv_d_y == None:
         pass
      elif isinstance(rv_d_y, DRV):
         (y,s) = rv_d_y.sample()
         m.y = y
         m.set_state(s)
         #print "edge=",edge
      else:
         m.y = rv_d_y[0]
         m.set_state(rv_d_y[1])
      return m.y

   def set_state(m, n):
      '''override function to set the next state n'''
      raise Exception("%s is not overrided!"%function_name())

   def get_state(m):
      '''override function to get the current state'''
      raise Exception("%s is not overrided!"%function_name())

   def state_to_s(m):
      ''' convert the current state to a string'''
      s =""; i = 0
      state = m.get_state()
      if isinstance(state, str) :
         s = state
      elif hasattr(state, '__iter__'):  
         for e in m.get_state():
            if i != 0: s += ","
            s += str(e); i += 1
      else:
         s = str(state)
      return s
   
if __name__ == "__main__":
   print 'mini test of FSDEVS'
   fg = FSDEVS("hmh")
   print fg

